//
//  KLRequest.m
//  KoalaUtilKit
//
//  Created by Tommy on 15/1/6.
//  Copyright (c) 2015年 Koala Team. All rights reserved.
//

#import "KLRequest.h"
#import "extscope.h"
#import "KLTransformer.h"
#import "KLError.h"

static NSMutableArray *klRequestList = nil;

@implementation KLRequest
@synthesize executing = _executing;
@synthesize finished = _finished;


- (instancetype)initWithBlock:(KLRequestBlock)requestBlock{
    if(self = [self initWithParams:nil withTransformer:nil andRequestBlock:requestBlock]){
    }
    return self;
}
- (instancetype)initWithParams:(NSDictionary*)params andTransformer:(id<KLITransformer>)transformer{
    if(self = [self initWithParams:params withTransformer:transformer andRequestBlock:nil]){
    }
    return self;
}
- (instancetype)initWithTransformer:(KLTransformer*)transformer andRequestBlock:(KLRequestBlock)requestBlock{
    if(self = [self initWithParams:nil withTransformer:transformer andRequestBlock:requestBlock]){
    }
    return self;
}
- (instancetype)initWithParams:(NSDictionary*)params{
    if(self = [self initWithParams:params withTransformer:nil andRequestBlock:nil]){
    }
    return self;
}

- (instancetype)initWithParams:(NSDictionary*)params andRequestBlock:(KLRequestBlock)requestBlock{
    if(self = [self initWithParams:params withTransformer:nil andRequestBlock:requestBlock]){
    }
    return self;
}
- (instancetype)initWithParams:(NSDictionary*)params withTransformer:(KLTransformer*)transformer andRequestBlock:(KLRequestBlock)requestBlock{
    if(self = [super init]){
        _response = [NSNull null];
        _requestBlock = [requestBlock copy];
        _transformer = transformer;
        _params = [params copy];
    }
    return self;
}

- (RACSignal *)startRequest{
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self);
        [self start];
        
        [[RACObserve(self, isFinished) ignore:@(NO)] subscribeNext:^(NSNumber *finished) {
            if(self.error){
                [subscriber sendError:self.error];
            }else{
                [[[RACSignal defer:^RACSignal *{
                    return [RACSignal return:self.response];
                }]flattenMap:^RACStream *(id value) {
                    return _transformer?[_transformer transform:self.response]:[RACSignal return:self.response];
                }]subscribeNext:^(id x) {
                    [subscriber sendNext:x];
                } error:^(NSError *error) {
                    [subscriber sendError:error];
                } completed:^{
                    [subscriber sendCompleted];
                }];
            }
            
        }];
        
        RACDisposable *dispose = [RACDisposable disposableWithBlock:^{
            [self cancel];
        }];
        
        [RACObserve(self, isCancelled) subscribeNext:^(NSNumber *canceled) {
            if([canceled boolValue]){
                [dispose dispose];
            }
        }];
        return dispose;
    }];
}
- (void)reset{
    _response = nil;
    _progress = 0.0f;
    _error = nil;
    self.finished = NO;
    self.executing = NO;
    
}
- (RACSignal *)restart{
    [self reset];
    return [self startRequest];
}

- (void)setFinished:(BOOL)finished {
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

- (void)setExecuting:(BOOL)executing {
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}
- (BOOL)isConcurrent {
    return NO;
}
- (void)start{
    @synchronized(self){
        if (self.isCancelled) {
            self.finished = YES;
            [self reset];
            return;
        }
    }
    self.executing = YES;
    @try {
        [self addToList];
        [self main];
        if(self.isCancelled){
            [self reset];
        }
    }
    @catch (NSException *exception) {
        self.error = [NSError errorWithDomain:KLExceptionErrorDomain code:KLExceptionErrorCodeException userInfo:exception.userInfo];
    }
    @finally {
        self.executing = NO;
        self.finished = YES;
        [self removeFromList];
    }
}
- (void)cancel{
    if (self.isFinished) return;
    self.executing = NO;
    [super cancel];
}
- (void)main{
    if(self.requestBlock){
        self.requestBlock(self);
    }else{
        [self doRequest];
    }
}
- (void)doRequest{

}

- (void)addToList{
    @synchronized(self){
        if(!klRequestList){
            klRequestList = [NSMutableArray new];
        }
        if(![klRequestList containsObject:self]){
            [klRequestList addObject:self];
        }
    }
}
- (void)removeFromList{
    @synchronized(self){
        if([klRequestList containsObject:self]){
            [klRequestList removeObject:self];
        }
    }
}

@end
